#ifndef TASKEXECUTOR_H_
#define TASKEXECUTOR_H_

#include <functional>
#include <memory>
#include <atomic>
#include <thread>
#include <unordered_map>
#include "TaskQueue.h"

namespace toolkit {

// 前置声明
class TaskExecutor;
class TaskCancelable;

/**
 * @brief 线程负载计数器
 */
class ThreadLoadCounter {
public:
    ThreadLoadCounter() = default;
    ~ThreadLoadCounter() = default;

    /**
     * @brief 增加负载计数
     */
    void addLoad() {
        ++_load;
    }

    /**
     * @brief 减少负载计数
     */
    void reduceLoad() {
        --_load;
    }

    /**
     * @brief 获取当前负载值
     */
    int getLoad() const {
        return _load;
    }

private:
    std::atomic<int> _load{0};
};

/**
 * @brief 任务取消接口
 */
class TaskCancelable {
public:
    using Ptr = std::shared_ptr<TaskCancelable>;
    virtual ~TaskCancelable() = default;

    /**
     * @brief 取消任务
     */
    virtual void cancel() = 0;

    /**
     * @brief 任务是否已取消
     */
    virtual bool isCanceled() const = 0;
};

/**
 * @brief 可取消任务实现类
 */
class TaskCancelableImp : public TaskCancelable {
public:
    using Ptr = std::shared_ptr<TaskCancelableImp>;

    /**
     * @brief 构造函数
     */
    TaskCancelableImp() = default;

    /**
     * @brief 析构函数
     */
    ~TaskCancelableImp() override = default;

    /**
     * @brief 取消任务
     */
    void cancel() override {
        _canceled = true;
    }

    /**
     * @brief 任务是否已取消
     */
    bool isCanceled() const override {
        return _canceled;
    }

private:
    std::atomic<bool> _canceled{false};
};

/**
 * @brief 任务执行器接口
 */
class TaskExecutor : public std::enable_shared_from_this<TaskExecutor> {
public:
    using Ptr = std::shared_ptr<TaskExecutor>;
    using Task = std::function<void()>;

    virtual ~TaskExecutor() = default;

    /**
     * @brief 异步执行任务
     * @param task 任务函数
     * @param may_sync 是否允许同步执行
     * @return 任务取消对象
     */
    virtual TaskCancelable::Ptr async(Task task, bool may_sync = true) = 0;

    /**
     * @brief 异步执行任务，优先执行
     * @param task 任务函数
     * @param may_sync 是否允许同步执行
     * @return 任务取消对象
     */
    virtual TaskCancelable::Ptr async_first(Task task, bool may_sync = true) = 0;

    /**
     * @brief 获取任务执行器负载
     * @return 负载值
     */
    virtual int getLoad() = 0;
};

/**
 * @brief 任务执行器获取接口
 */
class TaskExecutorGetter {
public:
    using Ptr = std::shared_ptr<TaskExecutorGetter>;
    virtual ~TaskExecutorGetter() = default;

    /**
     * @brief 获取任务执行器
     * @return 任务执行器
     */
    virtual TaskExecutor::Ptr getExecutor() = 0;
};

/**
 * @brief 任务执行器实现类
 */
class TaskExecutorImp : public TaskExecutor {
public:
    using Ptr = std::shared_ptr<TaskExecutorImp>;

    /**
     * @brief 构造函数
     * @param thread_num 线程数量
     */
    TaskExecutorImp(size_t thread_num = 1);

    /**
     * @brief 析构函数
     */
    ~TaskExecutorImp() override;

    /**
     * @brief 异步执行任务
     * @param task 任务函数
     * @param may_sync 是否允许同步执行
     * @return 任务取消对象
     */
    TaskCancelable::Ptr async(Task task, bool may_sync = true) override;

    /**
     * @brief 异步执行任务，优先执行
     * @param task 任务函数
     * @param may_sync 是否允许同步执行
     * @return 任务取消对象
     */
    TaskCancelable::Ptr async_first(Task task, bool may_sync = true) override;

    /**
     * @brief 获取任务执行器负载
     * @return 负载值
     */
    int getLoad() override;

private:
    /**
     * @brief 线程函数
     */
    void run();

private:
    size_t _thread_num;
    std::atomic<bool> _exit_flag{false};
    ThreadLoadCounter _thread_load;
    TaskQueue<Task> _task_queue;
    std::vector<std::thread> _threads;
};

/**
 * @brief 任务执行器获取实现类
 */
class TaskExecutorGetterImp : public TaskExecutorGetter {
public:
    using Ptr = std::shared_ptr<TaskExecutorGetterImp>;

    /**
     * @brief 构造函数
     * @param executor 任务执行器
     */
    TaskExecutorGetterImp(const TaskExecutor::Ptr &executor);

    /**
     * @brief 获取任务执行器
     * @return 任务执行器
     */
    TaskExecutor::Ptr getExecutor() override;

private:
    TaskExecutor::Ptr _executor;
};

} /* namespace toolkit */

#endif /* TASKEXECUTOR_H_ */